package com.lifeng.config;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.connection.CachingConnectionFactory;
import org.springframework.amqp.rabbit.connection.ConnectionFactory;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

import java.io.UnsupportedEncodingException;

/**
 * Created by lifeng on 2018/12/12.
 * 配置rabbit的连接,此类不可以不配,springboot内部装配
 * 此类可以自定义一些连接属性
 */
@Configuration
public class RabbitConfig {
    @Value("${spring.rabbitmq.host}")
    private String host;
    @Value("${spring.rabbitmq.port}")
    private int port;

    @Value("${spring.rabbitmq.username}")
    private String username;
    @Value("${spring.rabbitmq.password}")
    private String password;

    @Value("${spring.rabbitmq.virtual-host}")
    private String virtualHost;
    @Bean
    public ConnectionFactory connectionFactory() {
        CachingConnectionFactory connectionFactory = new CachingConnectionFactory(host,port);
        connectionFactory.setUsername(username);
        connectionFactory.setPassword(password);
        connectionFactory.setVirtualHost(virtualHost);
        connectionFactory.setRequestedHeartBeat(5);
        //可以配置连接属性
        connectionFactory.setConnectionCacheSize(10);//缓存连接
        connectionFactory.setCacheMode(CachingConnectionFactory.CacheMode.CONNECTION);
        return connectionFactory;
    }

    @Bean
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    //如果要实现消息确认机制，必须是prototype类型
    public RabbitTemplate rabbitTemplate() {
        final Logger log = LoggerFactory.getLogger(RabbitTemplate.class);
        RabbitTemplate template = new RabbitTemplate(connectionFactory());

        /**
         * ReturnCallback接口
         * 消息是否从Exchange路由到Queue, 注意: 这是一个失败回调, 只有消息从Exchange路由到Queue失败才会回调这个方法
         * setReturnCallback回调必须设置mandatory=true, 否则Exchange没有找到Queue就会丢弃掉消息, 而不会触发回调
         * yml需要配置 publisher-returns: true
         */
         /*template.setMandatory(true);
         template.setReturnCallback(new RabbitTemplate.ReturnCallback() {
             @Override
             public void returnedMessage(Message message,int replyCode, String replyText, String exchange, String routingKey) {
                 try {
                     String msg = new String(message.getBody(),"UTF-8");
                     log.info("消息信息:"+message.getMessageProperties().toString());
                     log.info("replyCode:{},replyText:{},exchange:{},routingKey:{}",replyCode,replyText,exchange,routingKey);
                 } catch (UnsupportedEncodingException e) {
                     log.error("转换错误",e);
                 }
             }
         });*/

        // 消息确认, yml需要配置 publisher-confirms: true
        //消息是否成功发送到Exchange，ConfirmCallback接口用于实现消息发送到RabbitMQ交换器后接收ack回调
        //即消息发送到exchange  ack
        /*template.setConfirmCallback(new RabbitTemplate.ConfirmCallback() {
            @Override
            public void confirm(CorrelationData correlationData, boolean ack, String cause) {
                if (ack) {
                    log.debug("消息发送到exchange成功,id: {}", correlationData.getId());
                }else {
                    log.debug("消息发送到exchange失败,原因: {}", cause);
                }
            }
        });*/
        return template;
    }
}
